<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body{
            padding-bottom: 800px;
            padding-left: 30px;
        }
        table{
            border-collapse: collapse;
            border-spacing: 0px;
        }
        td{
            border:  1px solid black;
            padding: 4px 10px;
        }
    </style>
</head>
<body>
    <div id="app">
        <h4>watch 侦听器【监视器】</h4>
        <!-- 
            watch取值：Function |  { handler:Function,deep:Boolean(false),immediate:Boolean(false) }

            watch 侦听器
                + vue应用构建时以属性 watch ，取值对象进行定义
                + watch 对象中 ，key 取值 是 需要被额外监控的data或者computed中属性的名字 , **或者对象属性的取值路径字符串**
                                value 取值function， 描述变量变化时追加的额外执行方法
                                value 定义的回调方法，必然存在两个固定实参 newValue 和 oldValue
                                前者为修改后的新数据，后者为修改前旧数据
                + 因为watch回调方法采用的是，在变量劫持时为set提供额外回调，所以被定义了watch监视器的变量，
                                通过任意方式修改，都会触发回调函数
            watch 侦听器
                + 被定义的数据侦听器默认只能监控变量*栈*的数据变化，默认无法监控引用类型数据的*堆*数据变化
                + 如果需要完成对引用数据的*堆*的监控【深度监控】，可以通过取值 { deep:true } 方式开启
                    => 注意：如果深度侦听器触发的条件是堆中数据修改，此时栈地址未发生变化，
                             所以回调方法的 newValue和oldValue地址相同，数据相同
                + 如果希望侦听器函数在代码第一次运行时完成一次触发，可以通过取值 { immediate:true } 方式开启
         -->
        <p>msg:{{ msg }}</p>
        <input type="button" value="setMsg" @click="setMsg()">
        <br>
        <input type="text" v-model="msg" >
        <h5>vue数据仓库中的 msg 变量被修改的时候记录 所有修改日志</h5>
        <!-- <ul>
            <li v-for="log in logs">
                <span>{{ log.time }}</span>
                :
                <span>{{ log.value }}</span>
            </li>
        </ul> -->
        <input type="button" value="清空日志" @click="logs=[]">
        <table>
            <thead>
                <tr>
                    <td>序号</td>
                    <td>时间</td>
                    <td>修改前数据</td>
                    <td>修改后数据</td>
                </tr>
            </thead>
            <tbody>
                <tr v-for=" (log,i) in logs ">
                    <td>{{ i+1 }}</td>
                    <td>{{ log.time }}</td>
                    <td>{{ log.oldValue }}</td>
                    <td>{{ log.value }}</td>
                </tr>
            </tbody>
        </table>
        <hr>
        <p>user:{{ user }}</p>
        <p>监控user数据被修改;如果是年龄被修改,单独输出'user的年龄被修改:新值(?),旧值(?)'</p>
        <input v-model="user.name" type="text" />
        <input v-model="user.age" type="number" />
        <input type="button" value="重置user" @click="user={ name:'jack',age:44 }">
    </div>
    <script type="module">
        // 加载 Vue3 的ESM 模块文件
        import { createApp } from "../assets/vue3/vue.esm-browser.js"
        window.vm = createApp({
            data(){
                return {
                    msg:"msg",
                    logs:[
                        // {
                        //     time:new Date().toLocaleString(),
                        //     value:"msg",
                        //     oldValue:""
                        // }
                    ],
                    user:{
                        name:"tom",
                        age:23
                    }
                }
            },
            watch: {
                msg:function(nv,ov){
                    console.log("msg被修改时")
                    this.logs.push({
                        time:new Date().toLocaleString(),
                        // value:this.msg,
                        value:nv,
                        oldValue:ov
                    })
                },
                // 下述监视器只有在 logs 被重新赋值时才会触发，数组数据填充不会触发
                // logs(){
                //     console.log("logs数组被重新赋值")
                // }

                logs:{
                    // 变量变化的回调方法
                    handler(){
                        console.log("logs数组被修改[重新赋值，堆中数据调整]")
                    },
                    // 是否开启深度默认
                    deep:true
                },
                // user(){
                //     console.log("user对象被重置")
                // }
                user:{
                    handler(nv,ov){
                        console.log("user对象被重置或被修改:",nv,ov)
                    },
                    deep:true,
                    immediate:true
                },
                // 以路径规则定义的对象属性，只有在vue的watch配置中才功能效果
                "user.age":function(nv,ov){
                    console.log("user对象中的age被修改时才会触发:",nv,ov)
                },
            },
            methods: {
                setMsg() {
                    this.msg = Math.random();
                    // this.logs.push({
                    //     time:new Date().toLocaleString(),
                    //     value:this.msg
                    // })
                }
            },
        }).mount("#app")

        // Object.defineProperty({},key,{
        //     get(){},
        //     set(){
        //         watch[key]
        //     }
        // })
    </script>
</body>
</html>